const requireDirectory = require('require-directory')
const router = require('koa-router')
const cors = require('koa2-cors')
const koaBody = require('koa-body')
const jwt = require('koa-jwt')
const JWT = require('jsonwebtoken')
const AppRes = require('./app.res')
const AppConfig = require('./app.config')
const { User, Role, Permission } = require('../models/Middle')
const seq = require('../utils/seq')
// 参数验证
const parameter = require('koa-parameter')

// require-directory 实现路由自动注册
function loadRoutes (app) {
  requireDirectory(module, '../routes', {
    visit: obj => {
      if (obj instanceof router) {
        app.use(obj.routes(), obj.allowedMethods())
      }
    }
  })
}

const unlessPath = ['/api/user/login', '/api/user/register', '/api/resource/download', '/api/project/download']

// 处理其他中间件
function loadMiddleware (app) {
  // 处理跨域
  app.use(cors({
    credentials: true,
    allowMethods: ['GET', 'POST', 'DELETE', 'PUT'],
    allowHeaders: ['Content-Type', 'Authorization', 'Accept']
  }))
  // koa-body 处理post请求和上传文件
  app.use(koaBody({
    enableTypes: ['json', 'form', 'text'],
    multipart:true,  // 是否支持 multipart-formdata 的表单
    formidable: {
      maxFileSize: 200 * 1024 * 1024 // 文件最大支持的大小
    }
  }))
  // koa-jwt
  app.use(jwt({
    secret: AppConfig['secret'], passthrough:true }).unless({
      path: unlessPath
    })
  )
  // 参数验证
  app.use(parameter(app))
}

// 全局拦截器  放在其他路由之前
function loadInterceptor (app) {
  app.use(async (ctx, next) => {
    // await next()
    // 对登录、注册、下载等路由进行放行
    if (unlessPath.indexOf(ctx.request.url) !== -1 || ctx.request.url.split('?')[0] === unlessPath[2] || ctx.request.url.split('?')[0] === unlessPath[3]) { // /?search= 可能有问题
      await next()
    } else {
      // 判断 headers 中是否存在 authorization
      if (ctx.request.header && ctx.request.header.authorization === undefined) {
        ctx.body = {
          code: 401,
          msg: AppRes['401']
        }
      } else {
        // 若存在，传递 token 中的 uid
        try {
          ctx.uid = JWT.verify(ctx.request.header.authorization, AppConfig['secret']).data // 解密，获取payload
          await next()
        } catch (error) {
          // 捕获 jwt 的异常信息
          if (error.message === 'jwt expired') {
            ctx.body = {
              code: 500,
              msg: 'token 过期'
            }
          } else if (Error.message === 'jwt malformed') {
            ctx.body = {
              code: 500,
              msg: '令牌无效'
            }
          } else {
            ctx.body = {
              code: 500,
              msg: error.message
            }
          }
        }
      }
    }
  })
}

// 接口拦截 -> 查询该用户对应的角色下的接口是否存在
function apiInterceptor (app) {
  app.use(async (ctx, next) => {
    if (ctx.uid) {
      // console.log(ctx.request.url) // 当前请求接口
      const data = (await User.findOne({
        where: {
          id: ctx.uid
        },
        include: [
          {
            model: Role,
            as: 'ur',
            attributes: ['id'],
            through: { attributes: [] },
            include: [
              {
                model: Permission,
                as: 'rp'
              }
            ]
          }
        ]
      })).toJSON()
      const permsArr = []
      data.ur.forEach(item => {
        item.rp.forEach(ele => {
          permsArr.push(ele)
        })
      })
      // 处理请求接口 ? / 的问题 
      let url = ctx.request.url
      if (url.split('?')) url = url.split('?')[0]
      const regx = ['detail', 'deleteById', 'findByName', 'findCollectTypesById', 'getMenu']
      regx.forEach(item => {
        // 将 regx 替换为 regx/:id （修改，后续还要加用户id）
        if (url.indexOf(item) !== -1) {
          url = url.replace(new RegExp(`${item}\/.*`), `${item}/:id`)
        }
      })
      const res = permsArr.filter(item => {
        return url === item.path && item.type.toLowerCase() === ctx.request.method.toLowerCase()
      })
      if (res.length === 0) {
        ctx.body = {
          code: 401,
          msg: AppRes['401']
        }
      } else {
        await next()
      }
    } else {
      await next()
    }
  })
}



module.exports = {
  loadRoutes,
  loadMiddleware,
  loadInterceptor,
  apiInterceptor
}
